package com.example.mywebrtc;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

import org.json.JSONObject;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera2Enumerator;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private SurfaceViewRenderer mySurfaceView;
    private PeerConnectionFactory peerConnectionFactory;
    private VideoCapturer mVideoCapture;
    private VideoCapturer mRemoteVideoCapture;
    private EglBase.Context eglBaseContext;
    private SurfaceViewRenderer remoteSurfaceView;
    private MediaStream mediaStreamLocal;
    private MediaStream mediaStreamRemote;
    private PeerConnection mPeerConnection;
    private PeerConnection peerConnectionLocal;
    private PeerConnection peerConnectionRemote;
    private HashMap<String, PeerConnection> peerConnectionMap;
    private List<PeerConnection.IceServer> iceServers;
    private WebRtcSurfaceViewRenderer webRtcSurfaceViewRenderer;
    private WebRtcSurfaceViewInit webRtcSurfaceViewInit;
    private VideoTrack mVideoTrack;
    private AudioTrack mAudioTrack;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        PermissionsInitManager.initPermission(this);
        initPeerConnect();

        mySurfaceView = findViewById(R.id.localView);
        remoteSurfaceView = findViewById(R.id.RemoteView);
        webRtcSurfaceViewRenderer = findViewById(R.id.webrtc);
        webRtcSurfaceViewInit = new WebRtcSurfaceViewInit();
        webRtcSurfaceViewRenderer.setOnSurfaceInitFinish(webRtcSurfaceViewInit);

        // create AudioSource
        AudioSource audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
        mAudioTrack = peerConnectionFactory.createAudioTrack("101", audioSource);

        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", eglBaseContext);

        // create VideoCapturer
        mVideoCapture = createCameraCapturer(true);
        VideoSource videoSource = peerConnectionFactory.createVideoSource(mVideoCapture.isScreencast());
        mVideoCapture.initialize(surfaceTextureHelper,this,videoSource.getCapturerObserver());
        mVideoCapture.startCapture(480, 640, 30);

        mySurfaceView.setMirror(true);
        mySurfaceView.init(eglBaseContext, null);

        // create VideoTrack
        mVideoTrack = peerConnectionFactory.createVideoTrack("102", videoSource);
        // display in localView
        //videoTrack.addSink(webRtcSurfaceViewRenderer.SelfViewRenderer());

        //模拟远端
//        SurfaceTextureHelper surfaceTextureHelperRemote = SurfaceTextureHelper.create("RemoteCaptureThread", eglBaseContext);
//        mRemoteVideoCapture = createCameraCapturer(false);
//        VideoSource remoteVideoSource = peerConnectionFactory.createVideoSource(mRemoteVideoCapture.isScreencast());
//        mRemoteVideoCapture.initialize(surfaceTextureHelperRemote,this,remoteVideoSource.getCapturerObserver());
//        mRemoteVideoCapture.startCapture(480,640,30);
//
        remoteSurfaceView.setMirror(false);
        remoteSurfaceView.init(eglBaseContext,null);
//        VideoTrack remoteVideoTrack = peerConnectionFactory.createVideoTrack("102",remoteVideoSource);

        mediaStreamLocal = peerConnectionFactory.createLocalMediaStream("local");
        mediaStreamLocal.addTrack(mVideoTrack);
        mediaStreamLocal.addTrack(mAudioTrack);

//        mediaStreamRemote = peerConnectionFactory.createLocalMediaStream("remote");
//        mediaStreamRemote.addTrack(remoteVideoTrack);

        SignalingClient.get().setCallback(new PeerConnectCallBack());

        //建立连接
        String name = getIntent().getStringExtra("room");
        String toId = getIntent().getStringExtra("id");
        SignalingClient.get().connection(name, toId);
    }

    private synchronized PeerConnection getOrCreatePeerConnection(String socketId) {
        PeerConnection peerConnection = peerConnectionMap.get(socketId);
        if (peerConnection != null) {
            return peerConnection;
        }
        peerConnection = peerConnectionFactory.createPeerConnection(iceServers,
                new PeerConnectionObserver("create peerConn"){

                    @Override
                    public void onIceCandidate(IceCandidate iceCandidate) {
                        super.onIceCandidate(iceCandidate);
                        SignalingClient.get().sendIceCandidate(iceCandidate,socketId);
                    }

                    @Override
                    public void onAddStream(MediaStream mediaStream) {
                        super.onAddStream(mediaStream);
                        VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                webRtcSurfaceViewRenderer.createSurface(socketId,remoteVideoTrack);
                            }
                        });
                    }
                });
        peerConnection.addStream(mediaStreamLocal);
        peerConnectionMap.put(socketId,peerConnection);
        return peerConnection;
    }

    /**
     * 单人拨打，建立连接，废弃不用
     */
    private void call() {
        mPeerConnection = peerConnectionFactory.createPeerConnection(iceServers,
                new PeerConnectionObserver("connect location"){
                    @Override
                    public void onIceCandidate(IceCandidate iceCandidate) {
                        super.onIceCandidate(iceCandidate);
                       // SignalingClient.get().sendIceCandidate(iceCandidate);
                    }

                    @Override
                    public void onAddStream(MediaStream mediaStream) {
                        super.onAddStream(mediaStream);
                        VideoTrack videoTrack = mediaStream.videoTracks.get(0);
                        videoTrack.addSink(remoteSurfaceView);
                    }
                });
        mPeerConnection.addStream(mediaStreamLocal);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //通过getMenuInflater()方法获得MenuInflate对象，通过MenuInflate对象的inflate方法创建活动菜单
        getMenuInflater().inflate(R.menu.menu,menu);
        return true;
    }

    private VideoCapturer createCameraCapturer(boolean isFront) {
        Camera2Enumerator enumerator = new Camera2Enumerator(this);
        final String[] deviceNames = enumerator.getDeviceNames();

        if (deviceNames.length == 0) {
            return null;
        }

        for (String deviceName : deviceNames) {
            if (isFront) {
                if (enumerator.isFrontFacing(deviceName)) {
                    return enumerator.createCapturer(deviceName,null);
                }
            } else {
                if (enumerator.isBackFacing(deviceName)) {
                    return enumerator.createCapturer(deviceName,null);
                }
            }
        }

        return enumerator.createCapturer(deviceNames[0],null);

    }

    private void initPeerConnect() {
        peerConnectionMap = new HashMap<>();
        iceServers = new ArrayList<>();
        iceServers.add(PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").
                createIceServer());

        eglBaseContext =  EglBase.create().getEglBaseContext();

        PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions
                .builder(this)
                .createInitializationOptions());
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        //视频解码
        DefaultVideoEncoderFactory defaultVideoEncoderFactory =
                new DefaultVideoEncoderFactory(eglBaseContext,true,true);
        //视频解码
        DefaultVideoDecoderFactory defaultVideoDecoderFactory =
                new DefaultVideoDecoderFactory(eglBaseContext);
        peerConnectionFactory = PeerConnectionFactory.builder()
                .setVideoEncoderFactory(defaultVideoEncoderFactory)
                .setVideoDecoderFactory(defaultVideoDecoderFactory)
                .createPeerConnectionFactory();
    }

    @Override
    protected void onStart() {
        super.onStart();
        //mVideoCapture.startCapture(720, 1280, 30);
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    class PeerConnectCallBack implements SignalingClient.Callback{

        @Override
        public void onCreateRoom() {

        }

        @Override
        public void onPeerJoined(String socketId) {
            PeerConnection peerConnection = getOrCreatePeerConnection(socketId);
            peerConnection.createOffer(new SdbObserverInstance("createOfferSdp:" + socketId) {
                @Override
                public void onCreateSuccess(SessionDescription sessionDescription) {
                    super.onCreateSuccess(sessionDescription);
                    peerConnection.setLocalDescription(new SdbObserverInstance("setLocalSdp:" + socketId), sessionDescription);
                    SignalingClient.get().sendSessionDescription(sessionDescription, socketId);
                }
            }, new MediaConstraints());
        }

        @Override
        public void onSelfJoined() {

        }

        @Override
        public void onPeerLeave(String msg) {
            PeerConnection peerConnection = getOrCreatePeerConnection(msg);
            peerConnection.close();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(),msg + "已离开",Toast.LENGTH_SHORT).show();
                    webRtcSurfaceViewRenderer.removeSurface(msg);
                }
            });
        }

        @Override
        public void onOfferReceived(JSONObject data) {
            runOnUiThread(() -> {
                final String socketId = data.optString("from");
                PeerConnection peerConnection = getOrCreatePeerConnection(socketId);
                peerConnection.setRemoteDescription(new SdbObserverInstance("localSetRemote"),
                        new SessionDescription(SessionDescription.Type.OFFER, data.optString("sdp")));
                peerConnection.createAnswer(new SdbObserverInstance("localAnswerSdp") {
                    @Override
                    public void onCreateSuccess(SessionDescription sdp) {
                        super.onCreateSuccess(sdp);
                        peerConnection.setLocalDescription(new SdbObserverInstance("localSetLocal"), sdp);
                        SignalingClient.get().sendSessionDescription(sdp,socketId);
                    }
                }, new MediaConstraints());

            });
        }

        @Override
        public void onAnswerReceived(JSONObject data) {
            String socketId = data.optString("from");
            PeerConnection peerConnection = getOrCreatePeerConnection(socketId);
            peerConnection.setRemoteDescription(new SdbObserverInstance("localSetRemote"),
                    new SessionDescription(SessionDescription.Type.ANSWER,
                            data.optString("sdp")));
        }

        @Override
        public void onIceCandidateReceived(JSONObject data) {
            String socketId = data.optString("from");
            PeerConnection peerConnection = getOrCreatePeerConnection(socketId);
            peerConnection.addIceCandidate(new IceCandidate(
                    data.optString("id"),
                    data.optInt("label"),
                    data.optString("candidate")
            ));
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        SignalingClient.get().leaveRoom();
        for (String key:peerConnectionMap.keySet()) {
            peerConnectionMap.get(key).close();
        }
        try {
            mVideoCapture.stopCapture();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        peerConnectionFactory.dispose();
    }

    class WebRtcSurfaceViewInit implements WebRtcSurfaceViewRenderer.OnSurfaceInitFinish{

        @Override
        public void onFinishSelf() {
            SurfaceViewRenderer surfaceViewRenderer = webRtcSurfaceViewRenderer.SelfViewRenderer();
            surfaceViewRenderer.setMirror(true);
            surfaceViewRenderer.init(eglBaseContext,null);
            mVideoTrack.addSink(surfaceViewRenderer);
        }

        @Override
        public void OnChildFinish(SurfaceViewRenderer renderer, VideoTrack videoTrack) {
            renderer.setMirror(false);
            renderer.init(eglBaseContext, null);
            videoTrack.addSink(renderer);
        }
    }
}
